/**
 * @description 粘贴 text html
 * @author wangfupeng
 */

import Editor from "../../editor/index"
import { getPasteText, getPasteHtml } from "../paste/paste-event"
import { isFunction } from "../../utils/util"
import { urlRegex } from "../../utils/const"
import $, { DomElement } from "../../utils/dom-core"

/**
 * 格式化html
 * @param val 粘贴的html
 * @author liuwei
 */
function formatHtml(val: string) {
	let pasteText = val
	// div 全部替换为 p 标签
	pasteText = pasteText.replace(/<div>/gim, "<p>").replace(/<\/div>/gim, "</p>")
	// 不允许空行，放在最后
	pasteText = pasteText.replace(/<p><\/p>/gim, "<p><br></p>")
	// 去除''
	return pasteText.trim()
}

/**
 * 格式化html
 * @param val 粘贴的html
 * @author liuwei
 */
function formatCode(val: string) {
	let pasteText = val.replace(/<br>|<br\/>/gm, "\n").replace(/<[^>]+>/gm, "")

	return pasteText
}

/**
 * 判断html是否使用P标签包裹
 * @param html 粘贴的html
 * @author luochao
 */
function isParagraphHtml(html: string): boolean {
	if (html === "") return false

	const container = document.createElement("div")
	container.innerHTML = html

	return container.firstChild?.nodeName === "P"
}

/**
 * 判断当前选区是否是空段落
 * @param topElem 选区顶层元素
 * @author luochao
 */
function isEmptyParagraph(topElem: DomElement | undefined): boolean {
	if (!topElem?.length) return false

	const dom = topElem.elems[0]

	return dom.nodeName === "P" && dom.innerHTML === "<br>"
}

/**
 * 粘贴文本和 html
 * @param editor 编辑器对象
 * @param pasteEvents 粘贴事件列表
 */
function pasteTextHtml(editor: Editor, pasteEvents: Function[]) {
	function fn(e: Event) {
		// 获取配置
		const config = editor.config
		const pasteFilterStyle = config.pasteFilterStyle
		const pasteIgnoreImg = config.pasteIgnoreImg
		const pasteTextHandle = config.pasteTextHandle

		// 获取粘贴的文字
		let pasteHtml = getPasteHtml(e as ClipboardEvent, pasteFilterStyle, pasteIgnoreImg)
		let pasteText = getPasteText(e as ClipboardEvent)

		pasteText = pasteText.replace(/\n/gm, "</p><p>")
		// 当前选区所在的 DOM 节点
		const $selectionElem = editor.selection.getSelectionContainerElem()
		if (!$selectionElem) {
			return
		}
		const nodeName = $selectionElem?.getNodeName()
		const $topElem = $selectionElem?.getNodeTop(editor)
		// 当前节点顶级可能没有
		let topNodeName: string = ""
		if ($topElem.elems[0]) {
			topNodeName = $topElem?.getNodeName()
		}
		// code 中只能粘贴纯文本
		if (nodeName === "CODE" || topNodeName === "PRE") {
			if (pasteTextHandle && isFunction(pasteTextHandle)) {
				// 用户自定义过滤处理粘贴内容
				pasteText = "" + (pasteTextHandle(pasteText) || "")
			}
			editor.cmd.do("insertHTML", formatCode(pasteText))
			return
		}

		// 如果用户开启闭粘贴样式注释则将复制进来为url的直接转为链接 否则不转换
		//  在群中有用户提到关闭样式粘贴复制的文字进来后链接直接转为文字了，不符合预期，这里优化下
		if (urlRegex.test(pasteText) && pasteFilterStyle) {
			return editor.cmd.do("insertHTML", `<a href="${pasteText}" target="_blank">${pasteText}</a>`) // html
		}
		// table 中（td、th），待开发。。。
		if (!pasteHtml) {
			return
		}
		try {
			// firefox 中，获取的 pasteHtml 可能是没有 <ul> 包裹的 <li>
			// 因此执行 insertHTML 会报错
			if (pasteTextHandle && isFunction(pasteTextHandle)) {
				// 用户自定义过滤处理粘贴内容
				pasteHtml = "" + (pasteTextHandle(pasteHtml) || "") // html
			}
			// 粘贴的html的是否是css的style样式
			let isCssStyle: boolean = !pasteHtml.includes(";base64,") && /[\.\#\@]?\w+[^{]+\{[^}]*\}/.test(pasteHtml) // eslint-disable-line

			// 经过处理后还是包含暴露的css样式则直接插入它的text
			if (isCssStyle && pasteFilterStyle) {
				console.log(pasteText)
				editor.cmd.do("insertHTML", `${formatHtml(pasteText)}`) // text
			} else {
				const html = formatHtml(pasteHtml)
				// 如果是段落，为了兼容 firefox 和 chrome差异，自定义插入
				if (isParagraphHtml(html)) {
					const $textEl = editor.$textElem
					$textEl.append($(html))
					// 如果选区是空段落，移除空段落
					if (isEmptyParagraph($topElem)) {
						$topElem.remove()
					}
					// 移动光标到编辑器最后的位置
					const lastEl = $textEl.last()
					if (!lastEl?.length) return
					editor.selection.moveCursor(lastEl.elems[0])
				} else {
					editor.cmd.do("insertHTML", `${formatHtml(pasteHtml)}`) // html
				}
			}
		} catch (ex) {
			// 此时使用 pasteText 来兼容一下
			if (pasteTextHandle && isFunction(pasteTextHandle)) {
				// 用户自定义过滤处理粘贴内容
				pasteText = "" + (pasteTextHandle(pasteText) || "")
			}
			editor.cmd.do("insertHTML", `${formatHtml(pasteText)}`) // text
		}
	}

	pasteEvents.push(fn)
}

export default pasteTextHtml
